﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using KxParser.Lexer.Pm;
using KxParser.Parser.LR0;

namespace KxParserTester
{
    class Program
    {
        static void Main(string[] args)
        {
            //var inputText = "((( PCS7(\"TiO2 v 12.04\") +  1 ))) > (1 + 9) ";
            //var inputText = "GamaSystem(\"Prvo zrno v pigm. po mikronizaciji\",\"13.26/A\") > (ZG(\"Prvo zrno v pigm. po mikronizaciji\",\"13.26/A\") - 1) in 2 > 3";

            var inputText = "(3+9)* 14";


            #region Lexical analysis

            #region Define tokens

            var tokenDefinitions = new List<TokenDefinition>();
            tokenDefinitions.Add(new TokenDefinition(@"\d+\,\d+([eE][-+]?\d+)?", "NUM_FLOAT"));
            tokenDefinitions.Add(new TokenDefinition(@"\d+", "NUM_INT"));

            tokenDefinitions.Add(new TokenDefinition(@"\+", "+"));
            tokenDefinitions.Add(new TokenDefinition(@"\-", "-"));
            tokenDefinitions.Add(new TokenDefinition(@"\*", "*"));
            tokenDefinitions.Add(new TokenDefinition(@"\/", "/"));

            tokenDefinitions.Add(new TokenDefinition(@"\(", "("));
            tokenDefinitions.Add(new TokenDefinition(@"\)", ")"));
            //defs.Add(new TokenDefinition(@"\$", "$"));
            tokenDefinitions.Add(new TokenDefinition(@"\s|\t|\r|\n|\u000C", "WHITESPACE"));
            
            #endregion Define tokens

            TextReader r = new StringReader(inputText);
            var pmLexer = new PmLexer(r, tokenDefinitions.ToArray(), new[]{" ", "(", ")"}, new[] { "WHITESPACE" });

            var defaultConsoleColor = Console.ForegroundColor;

            if (pmLexer.GetState() != PmLexer.ELexerState.OK)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Lexer initialization failed. State = " + pmLexer.GetState());
            }

            foreach (var errorToken in pmLexer.GetErrorTokens())
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Lexer error: unknown token {0} at position {1}-{2}!",
                                                errorToken.Content, errorToken.StartIndex, errorToken.EndIndex));
            }

            var allTokens = pmLexer.GetAllTokens();
            foreach (var token in allTokens)
            {
                Console.ForegroundColor = defaultConsoleColor;
                Console.WriteLine(token); // string.Format("{0} = '{1}'", token.Name, token.Content));
            }
            #endregion Lexical analysis

            

            #region Syntax analysis

            if (pmLexer.GetState() == PmLexer.ELexerState.OK)
            {
                var productions = new List<string>();
                productions.Add("S' -> m $");
                productions.Add("m -> m math_op a");
                productions.Add("m -> a");
                productions.Add("a -> num");
                productions.Add("a -> ( m )");

                productions.Add("math_op -> +");
                productions.Add("math_op -> -");
                productions.Add("math_op -> *");
                productions.Add("math_op -> /");
                productions.Add("num -> ( num )");
                productions.Add("num -> - num1");
                productions.Add("num -> num1");
                productions.Add("num1 -> NUM_FLOAT");
                productions.Add("num1 -> NUM_INT");

                var tokens = pmLexer.GetNonIgnoredTokens();
                var terminals = (from t in tokens select t.Name).Distinct().ToArray();

                var nonTerminals = new List<string>();
                nonTerminals.AddRange(new[] {"S'", "m", "a", "math_op", "num", "num1"});
                var lr0parser = new Lr0Parser(productions.ToArray(), terminals, nonTerminals.ToArray());
                var parserResult = lr0parser.Parse(tokens);

                if (!parserResult)
                {
                    var errorToken = lr0parser.GetErrorToken();
                    if (errorToken != null)
                    {

                        //_memo.IsValid = false;
                        if (!errorToken.Content.Equals("$"))
                            Console.WriteLine(string.Format("Syntax error: illegal character {0} at position {1}-{2}",
                                                            errorToken.Content, errorToken.StartIndex,
                                                            errorToken.EndIndex));
                        else
                            Console.WriteLine(string.Format("Syntax error: illegal end of input string"));
                    }
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("PARSE OK");
                }
            }


            #endregion Syntax analysis

            Console.ForegroundColor = defaultConsoleColor;
            Console.Write("Press any key...");
            Console.ReadKey();
        }
    }
}
